package com.hu.hutool.config;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * @Author CazCen
 * @Date 2021/10/24 19:09
 */

@Aspect
@Component
@Slf4j
public class WebLogAspect {

    private Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    private final static String httpStartTime = "HTTP_START_TIME";

    @Value("${spring.application.name:'application-name'}")
    private String applicationName;

    @Pointcut("execution(public * com.hu.hutool..controller..*(..))")
    private void webLog() {
    }

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        try {
            if (!logger.isInfoEnabled()) {
                log.info("切面处理,请打开logger日志配置信息");
                return;
            }
            // 请收请求内容，记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                log.error("切面处理 attributes is null");
                return;
            }
            HttpServletRequest request = attributes.getRequest();
            request.setAttribute(httpStartTime, System.currentTimeMillis());

            // 获取请求参数
            StringBuilder params = getParams(joinPoint);
            StringBuilder sb = new StringBuilder(1000);
            sb.append("\n=================" + applicationName + ":接口请求参数信息:=================\n");
            sb.append("Controller: ").append(joinPoint.getSignature().getDeclaringType()).append("\n");
            String methodName = joinPoint.getSignature().getName();
            sb.append("Method : ").append(methodName).append("\n");
            sb.append("Params : ").append(params).append("\n");
            sb.append("URI : ").append(request.getMethod()).append(" ").append(request.getRequestURI()).append("\n");
            //当前语言
            String language = request.getHeader("Accept-Language");
            sb.append("Language : ").append(language).append("\n");
            sb.append("=================" + applicationName + ":开始调用:【" + methodName + "】方法=================");
            // 记录下请求内容
            log.info(sb.toString());
        } catch (Exception e) {
            e.printStackTrace();
            logger.warn("切面处理前出错:{}", e);
        }
    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(JoinPoint joinPoint, Object ret) throws Throwable {
        if (!logger.isInfoEnabled()) {
            return;
        }
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return;
        }
        HttpServletRequest request = attributes.getRequest();

        // 计算花费的时间
        long ms = System.currentTimeMillis() - (long) request.getAttribute(httpStartTime);

        // 处理完请求，返回内容
        StringBuilder sb = new StringBuilder(1000);
        String methodName = joinPoint.getSignature().getName();
        sb.append("\n=================" + applicationName + ":结束调用【" + methodName + "】返回结果:=================\n");
        sb.append("Controller: ").append(joinPoint.getSignature().getDeclaringType()).append("\n");
        sb.append("Method    : ").append(methodName).append("\n");
        sb.append("URI       : ").append(request.getMethod()).append(" ").append(request.getRequestURI()).append("\n");
        sb.append("Params    : ").append(getParams(joinPoint)).append("\n");
        sb.append("return    : ").append(JSON.toJSONString(ret)).append("\n");
        sb.append("CostTime  : ").append(ms).append("ms\n");
        sb.append("=================" + applicationName + ":请求结束:=================");
        log.info(sb.toString());
    }


    private StringBuilder getParams(JoinPoint joinPoint) {
        StringBuilder params = new StringBuilder();
        for (Object arg : joinPoint.getArgs()) {
            try {
                if (!(arg instanceof ServletRequest)
                        && !(arg instanceof ServletResponse)
                        && !(arg instanceof MultipartFile)
                        && !(arg instanceof ModelAndView)
                        && !(arg instanceof Model)
                ) {
                    params.append(", ");
                    params.append(JSON.toJSONString(arg));

                }
            } catch (Exception e) {
                logger.warn("未知类型转换错误:" + arg.getClass().getSimpleName());
            }
        }
        return params;
    }


    private String getRequestId(String jsonParams) {
        String requestId = "";
        try {
            String requestIdKey = "requestId";
            if (jsonParams.indexOf(requestIdKey) == -1) {
                return "";
            }
            //json要是 用 {}包围的
            if (jsonParams.startsWith("{") && jsonParams.endsWith("}")) {
                JSONObject jsonObject = JSON.parseObject(jsonParams);
                if (Objects.isNull(jsonObject)) {
                    return "";
                }
                requestId = jsonObject.getString(requestIdKey);
                return Objects.isNull(requestId) ? "" : requestId;
            }

        } catch (Exception e) {
            log.error(jsonParams + " 参数转换为Json错误");
            return "";
        }
        return requestId;

    }

}
